package tk3.project.uploadservice;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Date;
import java.util.Iterator;
import java.util.Vector;



public class ServerWorker extends Thread{
	 private Socket socket = null;
	 private ObjectInputStream inFromClient;
	 private ObjectOutputStream outToClient;
	 private Server server;
	 private String storePath="";

	    public ServerWorker(Socket socket,Server server) {
		super("ServerWorker");
		this.socket = socket;
		this.server=server;
	    }

	    public void run() {
	    	//System.out.println("New Server Worker Thread");
	    	try {
	    		outToClient = new ObjectOutputStream(socket.getOutputStream());
	    		inFromClient = new ObjectInputStream(socket.getInputStream());
	    	      
	    		

	    	    try {
					handleRequest((Message)inFromClient.readObject());
				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	    		socket.close();
	    		System.out.print("...done");
	    	} 
			catch (IOException e) {
				e.printStackTrace();
			}
	    	System.out.println("");
	    }
	    
	    /**
	     * Processes new incoming messages
	     * @param msg - the received message
	     */
	    private synchronized void handleRequest(Message msg){
	    	System.out.print("Received Message of type "+ msg.getType()+"!");
	    	if(msg.getType()==1){
	    		System.out.print("Server received "+msg.getPictures().size()+" pictures!");
	    		if(msg.getPictures().get(0).getStream().equals(""))
	    			System.out.println("Picture0 is at:"+msg.getPictures().get(0).getLat()+" "+msg.getPictures().get(0).getLon());
	    		else
	    			System.out.println("Picture0 uploaded to Stream:"+msg.getPictures().get(0).getStream());
				receivePictures(msg.getPictures());
			}
			else if(msg.getType()==2){
				System.out.print("Server received Ack"+msg.getAcks()+"!");
			}
			
			else if(msg.getType()==3){
				System.out.print("Server received a picture request to position:"+msg.getLat()+" "+msg.getLon());
				submitPictures(getPicturesAround(msg.getLat(),msg.getLon(), msg.getRadius(), msg.getDate()));
			}
			else if(msg.getType()==4){
				System.out.print("Server received a picture request for Stream: "+msg.getStream()+"!");
				submitPictures(getPictureStream(msg.getStream(), msg.getPassword(),msg.getDate()));
			}
			else{
				System.out.print("Server received a message it can't handle!");
			}
	    }
	    
	    
	    
	    /**
	     * Submits pictures of a request to the client
	     * @param p - The pictures to be transmitted
	     */
	    private synchronized void submitPictures(Vector<Picture> p){
			try {
				System.out.print("Submitting around pics:"+p.size()+"!");
				outToClient.writeObject(new Message(p));
				outToClient.flush();
				Message msg=(Message)inFromClient.readObject();
				if(msg.getType()==2){
					System.out.print("Server transmitted pictures of the request correctly!");
				}
				else{
					System.out.print("Server didn't receive acks for the transmitted Files!");
				}
			} catch (IOException | ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
	    }
	    
	    /**
	     * Find pictures based on GPS position
	     * @param lat
	     * @param lon
	     * @param radius - the radius within new pictures are desired
	     * @param earliestDate - Date of the last picture received on the last download from the server
	     * @return A List of pictures satisfying the parameters
	     */
	    private synchronized Vector<Picture> getPicturesAround(double lat,double lon, int radius, Date earliestDate){
	    	Vector<Picture> ret=new Vector<Picture>();
	    	Iterator<Picture> it=server.getPictures().iterator();
	    	while(it.hasNext()){
	    		Picture p=it.next();
	    		//System.out.println("Distance: lat/lon"+p.getLat()+" "+p.getLon()+" ;"+lat+" "+lon+";"+p.distance(lat, lon));
	    		if(p.distance(lat,lon)<=radius&&p.getShareRadius()>=p.distance(lat,lon)&&p.isNewerThan(earliestDate)){
	    			ret.add(p);
	    		}
	    	}
	    	
	    	return ret;
	    }
	    /**
	     * Find Pictures based on a Stream name
	     * @param stream
	     * @param password
	     * @param earliestDate - Date of the last picture received on the last download from the server
	     * @return
	     */
	    private synchronized Vector<Picture> getPictureStream(String stream, String password, Date earliestDate){
	    	Vector<Picture> ret=new Vector<Picture>();
	    	Iterator<Picture> it=server.getPictures().iterator();
	    	while(it.hasNext()){
	    		Picture p=it.next();
	    		Date maxShareTime=new Date(p.getDate().getTime()+p.getShareDuration()*10000*360);//share duration in hours
	    		if(maxShareTime.before(new Date())){
	    			//delete pictures after max share duration
	    			server.removePicture(p);
	    		}
	    		//System.out.println("Distance: lat/lon"+p.getLat()+" "+p.getLon()+" ;"+lat+" "+lon+";"+p.distance(lat, lon));
	    		else if(p.isInStream(stream, password)&&p.isNewerThan(earliestDate)){
	    			ret.add(p);
	    		}
	    	}
	    	return ret;
	    }
	    
	    /**
	     * Handles new incoming pictures
	     * @param p
	     */
	    private synchronized void  receivePictures(Vector<Picture> p){
	    	for(Picture picture : p){
				picture.unloadNewPicture(storePath);
				picture.resetDate();
				server.addPicture(picture);
			}
	    	sendAck(p.size());
	    }
	    /**
	     * Acks the received pictures
	     * @param amount
	     */
	    private synchronized void sendAck(int amount){
	    	try {
				outToClient.writeObject(new Message(amount));
				outToClient.flush();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	    	
	    }
}
